package top.lingkang.fv.solon;

import org.noear.solon.core.aspect.Interceptor;
import org.noear.solon.core.aspect.Invocation;
import org.noear.solon.core.wrap.ParamWrap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.lingkang.finalvalidated.core.FinalValidator;
import top.lingkang.finalvalidated.core.ValidObject;
import top.lingkang.finalvalidated.handle.ValidHandle;
import top.lingkang.finalvalidated.utils.FinalValidatorUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lingkang
 * Created by 2024/3/5
 */
public class InterceptorFinalValidator implements Interceptor {
    private static final Logger log = LoggerFactory.getLogger(InterceptorFinalValidator.class);
    private static final Map<Parameter, ValidParamCache> cache = new ConcurrentHashMap<>();

    public InterceptorFinalValidator() {
        // 初始化
        FinalValidator.factory = new FinalValidatorFactorySolon();
        FinalValidator.init();
        log.info("初始化 final-validator 完成");
    }

    @Override
    public Object doIntercept(Invocation inv) throws Throwable {
        ParamWrap[] paramWraps = inv.method().getParamWraps();
        for (int i = 0; i < paramWraps.length; i++) {
            Parameter parameter = paramWraps[i].getParameter();
            ValidParamCache paramCache = cache.get(parameter);
            if (paramCache == null) {
                ValidObject validObject = parameter.getAnnotation(ValidObject.class);
                if (validObject != null && FinalValidator.supports(parameter.getType())) {
                    paramCache = new ValidParamCache();
                    paramCache.setClass(true);
                    if (validObject.value().length != 0) {
                        paramCache.setGroups(validObject.value());
                    }
                }
                if (paramCache == null) {
                    List<Annotation> list = FinalValidatorUtils.getValidParameter(parameter);
                    if (!list.isEmpty()) {
                        paramCache = new ValidParamCache();
                        paramCache.setClass(false);
                        List<ValidHandle> handles = new ArrayList<>();
                        paramCache.setHandles(handles);
                        for (Annotation annotation : list) {
                            handles.add(FinalValidatorUtils.annotationToValidHandle(null, parameter, annotation));
                        }
                    }
                }
                if (paramCache == null) {
                    paramCache = new ValidParamCache();
                    paramCache.setValid(false);
                } else {
                    paramCache.setValid(true);
                }

                cache.put(parameter, paramCache);
            }
            if (paramCache.isValid()) {
                if (paramCache.isClass()) {
                    if (paramCache.getGroups() != null) {
                        FinalValidator.valid(inv.args()[i], paramCache.getGroups());
                    } else {
                        FinalValidator.valid(inv.args()[i]);
                    }
                } else {
                    for (ValidHandle handle : paramCache.getHandles()) {
                        handle.valid(inv.args()[i]);
                    }
                }
            }
        }
        return inv.invoke();
    }

    public void clearCache() {
        cache.clear();
    }
}
